/**
 * 由于arr数据总是存储在一个object中所以每次读取的时候就知道，
 * 由于谁用到了依赖谁就是 那么谁用到arr型数据；而从object数据对象中获取arr数据
 * 而从object数据对象中获取arr数据自然就会触发arr的getter，所以我们就可以在getter中收集依赖。
 * 
 * 
 * 总结一句话就是：Array型数据还是在getter中收集依赖。
*/


/**
 * 思路分析
 *      Object的变化是通过setter来追中的，只有摸一个数据发生变化，就一定会触发这个数据上啊的setter。
 *      但是Array型数据没有setter怎么办？
 * 
 *       我们试想一下，要想让Array型数据发生变化，那必然就是操作了Array，而js中提供
 *       操作数组的的方法就那个几种，我们可以把他重写一遍，再不改变原有工能的前提下，我们为期新增一些其他功能，
 *       例如，下面这个例子：
 *       let arr = [1,2,3]
 *       Array.prototype.newPush = function (params) {
            console.log('arr被修改了')
            this.push('val')
         }
 * 
 * 
 *      在上面这个例子中，我们针对数组的原生push方法定义个一个新的newPush方法，这个newPush方法内部调用了原生push方法，
 *      这样就保证了新的newPush方法跟原生push方法具有相同的功能，而且我们还可以在新的newPush方法内部干一些别的事情，比如通知变化。
 *      是不是很巧妙？Vue内部就是这么干的
 * 
 * 
*/


/**
 *  数组方法拦截器
 *  基于上一小节的思想，在Vue中创建了一个数组方法拦截器，它拦截在数组实例与Array.prototype之间，
 *  在拦截器内重写了操作数组的一些方法，当数组实例使用操作数组方法时，其实使用的是拦截器中重写的方法，
 *  而不再使用Array.prototype上的原生方法。如下图所示：
 *  https://vue-js.com/learn-vue/assets/img/2.b446ab83.png
 * 
 * 
 *  经过整理，Array原型中可以改变数组自身内容的方法有7个，
 *  分别是：push,pop,shift,unshift,splice,sort,reverse。\
 *  那么源码中的拦截器代码如下：
 * 
 *  src/core/observer/array.js
*/
const arrayProto = Array.prototype;
//  创建一个对象作为拦截器
const arrayMethods = Object.create(arrayProto);
// 改变数组自身的7种方法
const methodsToPatch = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
]

/**
 * Intercept mutating methods and emit events
 * 
*/
methodsToPatch.forEach(function (methods) {
    const original = arrayProto[methods];  // 缓存原生方法
    Object.defineProperty(arrayMethods, methods, {
        enumerable:true,
        configurable:true,
        writable:true,
        value:function mutator(...args) {
            const result = original.apply(this, args)
            return result
        }
    })
})
